package gameState;

import java.io.Serializable;
import java.util.ArrayList;

public class Ring implements Serializable{

    private static final long serialVersionUID = 1L;

    private ArrayList<Player> ring = new ArrayList<Player>();
    private static final Ring RING_INSTANCE = new Ring();

    private Player me;
    
    private Ring(){
    }

//    public static synchronized Ring getInstance(){
//    	//TODO just for testing.....ho rimosso il singleton....RIMUOVERLO APPENA TERMINATO
//		//return RING_INSTANCE;
//    	return new Ring();
//	}
    
    public static synchronized Ring getInstance(){
		return RING_INSTANCE;
	}
	
	public int size(){
		return ring.size();
	}
	
	
	public ArrayList<Player> getRing() {
		return ring;
	}

	public void setRing(ArrayList<Player> ring) {
		this.ring = ring;
	}

	public Player getPlayer(int i){
		try{
			return this.ring.get(i);
			
		}catch(Exception e){
			System.out.println("- Excepition- [Ring || getPlayer()] Impossibile ottenere " +
					"il Player all'index: "+i+
					" this.ring.size()="+this.ring.size());
			return new Player();
		}
	}


    public void setMe(Player p){
        this.me=p;
    }

    public Player getMe(){
        return me;
    }

    public Player getMyNextPlayer(){
    	try{
	        for(int i=0; i<ring.size(); i++){
	            if(ring.get(i).equalPlayer(me)){
	                return ring.get(((i+1) % ring.size()));
	            }
	        }
    	}catch(Exception e){
			System.out.println("- Excepition- [Ring || getMyNextPlayer()] Impossibile ottenere " +
					"il mio nextPlayer "+
					" this.ring.size()="+this.ring.size());
			return new Player();
		}
        System.out.println("[Ring || getMyNextPlayer()] finito cilco for e NON trovato currentPlayer");
        return null;
    }


    public void addPlayerToRing(Player p){
    	try{
            ring.add(p);
    	
    	}catch(Exception e){
			System.out.println("- Excepition- [Ring || addPlayerToRing()] Impossibile aggiungere il Player " +
					"il Player: "+p.getName()+
					" this.ring.size()="+this.ring.size());
		}
    }


    public Player getSuccessivePlayer(Player p){
    	try{
	        for(int i=0; i<ring.size(); i++){
	            if(ring.get(i).getId()==p.getId()){
	                return ring.get(((i+1) % ring.size()));
	            }
	        }
	        
    	}catch(Exception e){
			System.out.println("- Excepition- [Ring || getSuccessivePlayer()] Impossibile ottenere " +
					"il Player successivo del Player "+p.getName()+
					" this.ring.size()="+this.ring.size());
			return new Player();
		}
    	
        System.out.println("[Ring || getSuccessivePlayer()] finito ciclo for e NON trovato currentPlayer");
        return null;
    }


    public void addPlayersList(ArrayList<Player> r){
    	try{
	        for(int i=0;i<r.size();i++){
				ring.add(r.get(i));
			}
    	
    	}catch(Exception e){
			System.out.println("- Excepition- [Ring || addPlayersList()] Impossibile aggiungere " +
					"l'arrayList di Player al ring;"+
					" this.ring.size()="+this.ring.size());
		}
    }


    public void addEntireRing(Ring r){
    	try{
	        for(int i=0;i<r.size();i++){
	        	ring.add(r.getPlayer(i));
	        }
	        
    	}catch(Exception e){
			System.out.println("- Excepition- [Ring || addEntireRing()] Impossibile aggiungere " +
					"l'intero ring in input al ring locale;"+
					" this.ring.size()="+this.ring.size());
		}
    }
    
    //TODO DA CONTROLLARE
    public boolean existPlayerInTheRing(Player p){
    	try{
	        for(int i=0; i<ring.size(); i++){
	            if(p.equalPlayer(ring.get(i))){
	        	//if(p.getId()==ring.get(i).getId()){
	                return true;
	            }
	        }
	        return false;
    	
    	}catch(Exception e){
			System.out.println("- Excepition- [Ring || existPlayerInTheRing()] Impossibile trovare " +
					"il Player : "+p.getName()+" nel ring; "+
					" this.ring.size()="+this.ring.size());
			return false;
		}
    }
    
    public boolean isSameRing(Ring r){
    	try{
	    	if(r.size()!=this.ring.size()){
	    		return false;
	    	}
	
			for(int i=0; i<r.size(); i++){
				if(!this.existPlayerInTheRing(r.getPlayer(i))){
					return false;
				}
			}
	    	return true;
    	}catch(Exception e){
			System.out.println("- Excepition- [Ring || isSameRing()] Impossibile controllare l'uguaglianza " +
					"tra il ring in input e quello locale; "+
					" this.ring.size()="+this.ring.size());
			return false;
		}
    }
    
    public boolean isSameRing(ArrayList<Player> players){
    	try{
	    	if(players.size()!=this.ring.size()){
	    		return false;
	    	}
	    	
			for(int i=0; i<players.size(); i++){
				if(!this.existPlayerInTheRing(players.get(i))){
					return false;
				}
			}
	    	return true;
	    
    	}catch(Exception e){
			System.out.println("- Excepition- [Ring || isSameRing()] Impossibile controllare l'uguaglianza " +
					"tra l'arrayList<Player> in input e il ring locale; "+
					" this.ring.size()="+this.ring.size());
			return false;
		}
    }

    public void repairRing(Ring r){
    	try{
	    	int size=this.size();
	    	int sizeR= r.size();
	    	int i=0;
	    	while((i<size) && (i<sizeR)){
	    		if(!r.existPlayerInTheRing(this.ring.get(i))){
					this.removePlayer(r.getPlayer(i));
					size--;
					i--;
				}
	    		i++;
	    	}
	    	
    	}catch(Exception e){
			System.out.println("- Excepition- [Ring || repairRing()] Impossibile riparare " +
					"il ring locale con il ring in input; "+
					" this.ring.size()="+this.ring.size());
		}
    }

    public void removePlayer(Player p){
    	boolean removed = false;
    	try{
	        int i = 0;
	        while((i<ring.size())&&(!removed)){
	            if(ring.get(i).equalPlayer(p)){
	        	//if(ring.get(i).getId()==p.getId()){
	                ring.remove(i);
	                removed = true;
	            }
	            i++;
	        }
	        
    	}catch(Exception e){
    		if(!removed){
				System.out.println("- Exception- [Ring || removePlayer()] Impossibile rimuovere " +
						"il Player "+p.getName()+ " dal ring locale;"+
						" this.ring.size()="+this.ring.size());
			}else{
				System.out.println("- Exception- [Ring || removePlayer()] Player "+p.getName()+
						" rimosso dal ring locale; ");
				e.printStackTrace();
			}
			
		}
    }

	public int getPlayerPosition(Player p){
		try{
			for(int i=0;i<ring.size();i++){
				if(p.equalPlayer(ring.get(i))){
					return i;
				}
			}
			return -1;
		
		}catch(Exception e){
			System.out.println("- Exception- [Ring || getPlayerPosition()] Impossibile ottenere " +
					"il Player "+p.getName()+" dal ring locale;"+
					" this.ring.size()="+this.ring.size());
			return -1;
		}
		
	}

        public void deleteRing(){
            ring.clear();
        }


        public void stampaRing(){
            stampaRing("");
        }
        

        public void stampaRing(String titolo){
            System.out.println(titolo);
            System.out.println("         [RING]");
            for(int i=0; i<ring.size(); i++){
                System.out.println("["+i+"]["+ring.get(i).getIp()+"]["+ring.get(i).getName()+"]");
            }
        }


        public boolean amIalone(){
            return (ring.size()==1 && ring.get(0).equalPlayer(me));
        }


}
